// class Greeter{
//     greeting:string;
//     constructor(msg:string){
//         this.greeting=msg;
//     }
//     greet(){
//         return "Hi," + this.greeting
//     }
// }

// let gretter = new Greeter('World');
// const m = gretter.greet();
// console.log(m);

//====================================↓   ↓   ↓   ↓====================================
//Dogs是一个派生类，它派生自Animals基类，通过extends关键字。 派生类通常被称作子类，基类通常被称作超类。
// class Animals {
//     move(distance:number=0){
//         console.log('Animals moved '+ distance + ' 米');
//     }
// }

// class Dogs extends Animals {
//     bark(){
//         console.log('woof!woof!');
//     }
// }

// const dog = new Dogs();
// dog.bark()
// dog.move(21)
// dog.bark()

//====================================↓   ↓   ↓   ↓====================================
// class Animalss {
//     name: string;
//     constructor(theName: string) { 
//         this.name = theName;
//     }
//     move(distanceInMeters: number = 0) {
//         console.log(`${this.name} moved ${distanceInMeters}m.`);
//     }
// }

// class Snake extends Animalss {
//     constructor(name: string) {
//          super(name); 
//         }
//     move(distanceInMeters = 5) {
//         console.log("Slithering...");
//         super.move(distanceInMeters);
//     }
// }

// class Horse extends Animalss {
//     // 派生类包含构造函数，必须调用一次super(), 它会执行基类的构造函数；在构造函数里访问this的属性之前，我们一定要调用super()
//     constructor(name: string) { 
//         super(name);
//      }
//      // 重写move方法，当父类和自己有相同方法时，会使用自己的
//     move(distanceInMeters = 45) {
//         console.log("Galloping...");
//         super.move(distanceInMeters);
//     }
// }

// let sam = new Snake("Sammy the Python");
// let tom: Animalss = new Horse("Tommy the Palomino");

// sam.move(3);
// tom.move(34);

//====================================↓   ↓   ↓   ↓====================================
// 默认成员都是public,Ans1等于与Ans2
class Ans1{
    name:string;
    constructor(theName:string){
        this.name=theName;
    }
    move(meters:number){
    }
}
class Ans2 {
    public name:string
    public constructor(theName:string) {
        this.name=theName;
    }
    public move(meters:number){
    }
}
// private私有
class Ans3 {
    private name:string;
    age:number;
}
// new Ans3().name; // 私有成员 报错，值能在定义那个类中使用
// new Ans3().age;

// protected 在定义的类及其子类 ，可以访问
class Person {
    protected name:string;
    public age:number;
    private money:number;
    constructor(theName:string,theAge:number) {
        this.name=theName;
        this.age=theAge;
        this.money=999;
    }
    fuck(){

    }
}

class Employee extends Person {
    private department:string;
    constructor(e_name:string,org:string) {
        // 子类中调用super，参数是父类constructor的形参，会传递过去。super()就是执行父类的构造函数是
        super(e_name,18)
        this.department=org
    }

    public getElevator(){
        console.log(this); // this里是父类和自己的属性
        return `Hello,my name is ${this.name} and I work in ${this.department}`
    }
}

let howard = new Employee('Howard','科技部');
// howard.getElevator()
// console.log(howard.getElevator());
// console.log(howard.name);//只能在类“Person”及其子类中访问

//====================================↓   ↓   ↓   ↓====================================
// readonly
class Octopus {
    readonly name: string;
    readonly numberOfLegs: number = 8;
    constructor (theName: string) {
        this.name = theName;
    }
}
let dad = new Octopus("Man with the 8 strong legs");
// dad.name = "Man with the 3-piece suit"; // 错误! name 是只读的.

//====================================↓   ↓   ↓   ↓====================================
// 参数属性 ,可以定义并初始化成员，不用额外先定义name，然后才在constructor通过形参赋值，this.name=name
class Animal2 {
    constructor(private name: string) { }
    move(distanceInMeters: number) {
        console.log(`${this.name} moved ${distanceInMeters}m.`);
    }
}

//====================================↓   ↓   ↓   ↓====================================
// 静态属性:存在于类本身上面而不是类的实例上
class Grid {
    static origin = {x: 0, y: 0};
    calculateDistanceFromOrigin(point: {x: number; y: number;}) {
        let xDist = (point.x - Grid.origin.x);
        let yDist = (point.y - Grid.origin.y);
        return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
    }
    constructor (public scale: number) { }
}

let grid1 = new Grid(1.0);  // 1x scale
let grid2 = new Grid(5.0);  // 5x scale

// console.log(grid1.calculateDistanceFromOrigin({x: 10, y: 10}));
// console.log(grid2.calculateDistanceFromOrigin({x: 10, y: 10}));

//====================================↓   ↓   ↓   ↓====================================
// 抽象类,做为其它派生类的基类使用。 它们一般不会直接被实例化
abstract class Department {

    constructor(public name: string) {
    }

    printName(): void {
        console.log('部门名称: ' + this.name);
    }

    abstract printMeeting(): void; // 必须在派生类中实现，可以理解，在这里定义，在派生类中具体实现
}

class AccountingDepartment extends Department {

    constructor() {
        super('高科技研究部'); // 在派生类的构造函数中必须调用 super()
    }

    printMeeting(): void {
        console.log('The Accounting Department meets each Monday at 10am.');
    }

    generateReports(): void {
        console.log('Generating accounting reports...');
    }
}

let department: Department; // 允许创建一个对抽象类型的引用
// department = new Department(); // 错误: 不能创建一个抽象类的实例
department = new AccountingDepartment(); // 允许对一个抽象子类进行实例化和赋值
department.printName();
department.printMeeting();
// department.generateReports(); // 错误: 方法在声明的抽象类中不存在



//====================================↓   ↓   ↓   ↓====================================
// 构造函数
// 这个编译成JS后是下面那样
class Greeter {
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    }
    greet() {
        return "Hello, " + this.greeting;
    }
}

let greeter: Greeter; //意思是Greeter类的实例的类型是Greeter
greeter = new Greeter("world");
console.log(greeter.greet());

// 编译后↓ ↓ 
// let Greeter = (function () {
//     function Greeter(message) {
//         this.greeting = message;
//     }
//     Greeter.prototype.greet = function () {
//         return "Hello, " + this.greeting;
//     };
//     return Greeter;
// })();

// let greeter;
// greeter = new Greeter("world");
// console.log(greeter.greet());


//====================================↓   ↓   ↓   ↓====================================
// 把类当做接口使用
class Point {
    x: number;
    y: number;
}

interface Point3d extends Point {
    z: number;
}

let point3d: Point3d = {x: 1, y: 2, z: 3};